import sys
import ply.yacc

import table_ast
import table_lexer

class TableParser:
    tokens = None

    def p_translation_unit_1(self, p):
        'translation_unit : external_declaration'
        p[0] = table_ast.TranslationUnit(None, p[1])

    def p_translation_unit_2(self, p):
        'translation_unit : translation_unit external_declaration'
        p[0] = table_ast.TranslationUnit(p[1], p[2])

    def p_external_declaration_1(self, p):
        'external_declaration : SEMI'
        pass

    def p_external_declaration_2(self, p):
        'external_declaration : PREPROCESSOR'
        p[0] = table_ast.Preprocessor(p[1])

    def p_external_declaration_3(self, p):
        'external_declaration : COMMENT'
        p[0] = table_ast.Comment(p[1])

    def p_external_declaration_4(self, p):
        'external_declaration : enum_definition'
        p[0] = p[1]

    def p_enum_definition(self, p):
        'enum_definition : ENUM ID LBRACE enum_declaration_list RBRACE'
        p[0] = table_ast.EnumDefinition(p[2], p[4])

    def p_enum_declaration_list_1(self, p):
        'enum_declaration_list : enum_declaration'
        p[0] = table_ast.EnumDeclarationList(None, p[1])

    def p_enum_declaration_list_2(self, p):
        'enum_declaration_list : enum_declaration_list enum_declaration'
        p[0] = table_ast.EnumDeclarationList(p[1], p[2])

    def p_enum_declaration_1(self, p):
        '''enum_declaration : COMMA
                            | SEMI'''
        pass

    def p_enum_declaration_2(self, p):
        'enum_declaration : COMMENT'
        p[0] = table_ast.Comment(p[1])

    def p_enum_declaration_3(self, p):
        'enum_declaration : ID'
        p[0] = table_ast.EnumDeclaration(p[1])

    def p_enum_declaration_4(self, p):
        '''enum_declaration : ID EQUALS ns_id
                            | ID EQUALS NUMBER'''
        p[0] = table_ast.EnumDeclaration(p[1], p[3])

    def p_ns_id_1(self, p):
        'ns_id : ID'
        p[0] = table_ast.NsIdList(None, p[1])

    def p_ns_id_2(self, p):
        'ns_id : ns_id NSCOLON ID'
        p[0] = table_ast.NsIdList(p[1], p[3])

    def p_error(self, t):
        if t:
            strpos = '%s(%d,%d)' % (self.lexer.file,
                t.lineno, self.lexer.find_column(self.lexer.input, t))
            print('%s: Syntax error at %s.' % (strpos, repr(t.value.value
                if isinstance(t.value, table_lexer.TableLexer.Token)
                else t.value)))
        else:
            print("%s: Syntax error at EOF." % self.lexer.file)
        sys.exit(1)

    def __init__(self, **kwargs):
        if not self.tokens:
            self.tokens = table_lexer.TableLexer.tokens
        self.yacc = ply.yacc.yacc(module=self, **kwargs)

    def parse(self, lexer):
        self.lexer = lexer
        return self.yacc.parse(lexer=self.lexer.lexer)
